define(["require", "exports", "vscode-languageserver-protocol", "vscode-languageclient/codeConverter", "vscode-languageclient/protocolConverter", "vscode-languageclient/utils/is", "vscode-languageclient/utils/async", "vscode-languageclient/utils/uuid"], function (require, exports, vscode_languageserver_protocol_1, c2p, p2c, Is, async_1, UUID) {
    /* --------------------------------------------------------------------------------------------
     * Copyright (c) Microsoft Corporation. All rights reserved.
     * Licensed under the MIT License. See License.txt in the project root for license information.
     * ------------------------------------------------------------------------------------------ */
    'use strict';
    Object.defineProperty(exports, "__esModule", { value: true });
    var TransportKind;
    (function (TransportKind) {
        TransportKind[TransportKind["stdio"] = 0] = "stdio";
        TransportKind[TransportKind["ipc"] = 1] = "ipc";
        TransportKind[TransportKind["pipe"] = 2] = "pipe";
    })(TransportKind = exports.TransportKind || (exports.TransportKind = {}));
    /**
     * An action to be performed when the connection is producing errors.
     */
    var ErrorAction;
    (function (ErrorAction) {
        /**
         * Continue running the server.
         */
        ErrorAction[ErrorAction["Continue"] = 1] = "Continue";
        /**
         * Shutdown the server.
         */
        ErrorAction[ErrorAction["Shutdown"] = 2] = "Shutdown";
    })(ErrorAction = exports.ErrorAction || (exports.ErrorAction = {}));
    /**
     * An action to be performed when the connection to a server got closed.
     */
    var CloseAction;
    (function (CloseAction) {
        /**
         * Don't restart the server. The connection stays closed.
         */
        CloseAction[CloseAction["DoNotRestart"] = 1] = "DoNotRestart";
        /**
         * Restart the server.
         */
        CloseAction[CloseAction["Restart"] = 2] = "Restart";
    })(CloseAction = exports.CloseAction || (exports.CloseAction = {}));
    class DefaultErrorHandler {
        constructor(name) {
            this.name = name;
            this.restarts = [];
        }
        error(_error, _message, count) {
            if (count && count <= 3) {
                return ErrorAction.Continue;
            }
            return ErrorAction.Shutdown;
        }
        closed() {
            this.restarts.push(Date.now());
            if (this.restarts.length < 5) {
                return CloseAction.Restart;
            }
            else {
                let diff = this.restarts[this.restarts.length - 1] - this.restarts[0];
                if (diff <= 3 * 60 * 1000) {
                    exports.vscode.Window.showErrorMessage(`The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`);
                    return CloseAction.DoNotRestart;
                }
                else {
                    this.restarts.shift();
                    return CloseAction.Restart;
                }
            }
        }
    }
    var RevealOutputChannelOn;
    (function (RevealOutputChannelOn) {
        RevealOutputChannelOn[RevealOutputChannelOn["Info"] = 1] = "Info";
        RevealOutputChannelOn[RevealOutputChannelOn["Warn"] = 2] = "Warn";
        RevealOutputChannelOn[RevealOutputChannelOn["Error"] = 3] = "Error";
        RevealOutputChannelOn[RevealOutputChannelOn["Never"] = 4] = "Never";
    })(RevealOutputChannelOn = exports.RevealOutputChannelOn || (exports.RevealOutputChannelOn = {}));
    var State;
    (function (State) {
        State[State["Stopped"] = 1] = "Stopped";
        State[State["Running"] = 2] = "Running";
    })(State = exports.State || (exports.State = {}));
    var ClientState;
    (function (ClientState) {
        ClientState[ClientState["Initial"] = 0] = "Initial";
        ClientState[ClientState["Starting"] = 1] = "Starting";
        ClientState[ClientState["StartFailed"] = 2] = "StartFailed";
        ClientState[ClientState["Running"] = 3] = "Running";
        ClientState[ClientState["Stopping"] = 4] = "Stopping";
        ClientState[ClientState["Stopped"] = 5] = "Stopped";
    })(ClientState || (ClientState = {}));
    const SupporedSymbolKinds = [
        vscode_languageserver_protocol_1.SymbolKind.File,
        vscode_languageserver_protocol_1.SymbolKind.Module,
        vscode_languageserver_protocol_1.SymbolKind.Namespace,
        vscode_languageserver_protocol_1.SymbolKind.Package,
        vscode_languageserver_protocol_1.SymbolKind.Class,
        vscode_languageserver_protocol_1.SymbolKind.Method,
        vscode_languageserver_protocol_1.SymbolKind.Property,
        vscode_languageserver_protocol_1.SymbolKind.Field,
        vscode_languageserver_protocol_1.SymbolKind.Constructor,
        vscode_languageserver_protocol_1.SymbolKind.Enum,
        vscode_languageserver_protocol_1.SymbolKind.Interface,
        vscode_languageserver_protocol_1.SymbolKind.Function,
        vscode_languageserver_protocol_1.SymbolKind.Variable,
        vscode_languageserver_protocol_1.SymbolKind.Constant,
        vscode_languageserver_protocol_1.SymbolKind.String,
        vscode_languageserver_protocol_1.SymbolKind.Number,
        vscode_languageserver_protocol_1.SymbolKind.Boolean,
        vscode_languageserver_protocol_1.SymbolKind.Array,
        vscode_languageserver_protocol_1.SymbolKind.Object,
        vscode_languageserver_protocol_1.SymbolKind.Key,
        vscode_languageserver_protocol_1.SymbolKind.Null,
        vscode_languageserver_protocol_1.SymbolKind.EnumMember,
        vscode_languageserver_protocol_1.SymbolKind.Struct,
        vscode_languageserver_protocol_1.SymbolKind.Event,
        vscode_languageserver_protocol_1.SymbolKind.Operator,
        vscode_languageserver_protocol_1.SymbolKind.TypeParameter
    ];
    const SupportedCompletionItemKinds = [
        vscode_languageserver_protocol_1.CompletionItemKind.Text,
        vscode_languageserver_protocol_1.CompletionItemKind.Method,
        vscode_languageserver_protocol_1.CompletionItemKind.Function,
        vscode_languageserver_protocol_1.CompletionItemKind.Constructor,
        vscode_languageserver_protocol_1.CompletionItemKind.Field,
        vscode_languageserver_protocol_1.CompletionItemKind.Variable,
        vscode_languageserver_protocol_1.CompletionItemKind.Class,
        vscode_languageserver_protocol_1.CompletionItemKind.Interface,
        vscode_languageserver_protocol_1.CompletionItemKind.Module,
        vscode_languageserver_protocol_1.CompletionItemKind.Property,
        vscode_languageserver_protocol_1.CompletionItemKind.Unit,
        vscode_languageserver_protocol_1.CompletionItemKind.Value,
        vscode_languageserver_protocol_1.CompletionItemKind.Enum,
        vscode_languageserver_protocol_1.CompletionItemKind.Keyword,
        vscode_languageserver_protocol_1.CompletionItemKind.Snippet,
        vscode_languageserver_protocol_1.CompletionItemKind.Color,
        vscode_languageserver_protocol_1.CompletionItemKind.File,
        vscode_languageserver_protocol_1.CompletionItemKind.Reference,
        vscode_languageserver_protocol_1.CompletionItemKind.Folder,
        vscode_languageserver_protocol_1.CompletionItemKind.EnumMember,
        vscode_languageserver_protocol_1.CompletionItemKind.Constant,
        vscode_languageserver_protocol_1.CompletionItemKind.Struct,
        vscode_languageserver_protocol_1.CompletionItemKind.Event,
        vscode_languageserver_protocol_1.CompletionItemKind.Operator,
        vscode_languageserver_protocol_1.CompletionItemKind.TypeParameter
    ];
    function ensure(target, key) {
        if (target[key] === void 0) {
            target[key] = {};
        }
        return target[key];
    }
    var DynamicFeature;
    (function (DynamicFeature) {
        function is(value) {
            let candidate = value;
            return candidate && Is.func(candidate.register) && Is.func(candidate.unregister) && Is.func(candidate.dispose) && candidate.messages !== void 0;
        }
        DynamicFeature.is = is;
    })(DynamicFeature || (DynamicFeature = {}));
    class DocumentNotifiactions {
        constructor(_client, _event, _type, _middleware, _createParams, _selectorFilter) {
            this._client = _client;
            this._event = _event;
            this._type = _type;
            this._middleware = _middleware;
            this._createParams = _createParams;
            this._selectorFilter = _selectorFilter;
            this._selectors = new Map();
        }
        static textDocumentFilter(selectors, any) {
            for (const selector of selectors) {
                if (exports.vscode.languages.match(selector, any)) {
                    return true;
                }
            }
            return false;
        }
        register(_message, data) {
            if (!data.registerOptions.documentSelector) {
                return;
            }
            if (!this._listener) {
                this._listener = this._event(this.callback, this);
            }
            this._selectors.set(data.id, data.registerOptions.documentSelector);
        }
        callback(data) {
            if (!this._selectorFilter || this._selectorFilter(this._selectors.values(), data)) {
                if (this._middleware) {
                    this._middleware(data, (data) => this._client.sendNotification(this._type, this._createParams(data)));
                }
                else {
                    this._client.sendNotification(this._type, this._createParams(data));
                }
                this.notificationSent(data);
            }
        }
        notificationSent(_data) {
        }
        unregister(id) {
            this._selectors.delete(id);
            if (this._selectors.size === 0 && this._listener) {
                this._listener.dispose();
                this._listener = undefined;
            }
        }
        dispose() {
            if (this._listener) {
                this._listener.dispose();
            }
        }
    }
    class DidOpenTextDocumentFeature extends DocumentNotifiactions {
        constructor(client, _syncedDocuments) {
            super(client, exports.vscode.workspace.onDidOpenTextDocument, vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type, client.clientOptions.middleware.didOpen, (any) => client.code2ProtocolConverter.asOpenTextDocumentParams(any), DocumentNotifiactions.textDocumentFilter);
            this._syncedDocuments = _syncedDocuments;
        }
        get messages() {
            return vscode_languageserver_protocol_1.DidOpenTextDocumentNotification.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync;
            if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) {
                this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } });
            }
        }
        register(message, data) {
            super.register(message, data);
            if (!data.registerOptions.documentSelector) {
                return;
            }
            let documentSelector = data.registerOptions.documentSelector;
            exports.vscode.workspace.textDocuments.forEach((textDocument) => {
                let uri = textDocument.uri.toString();
                if (this._syncedDocuments.has(uri)) {
                    return;
                }
                if (exports.vscode.languages.match(documentSelector, textDocument)) {
                    let middleware = this._client.clientOptions.middleware;
                    let didOpen = (textDocument) => {
                        this._client.sendNotification(this._type, this._createParams(textDocument));
                    };
                    if (middleware.didOpen) {
                        middleware.didOpen(textDocument, didOpen);
                    }
                    else {
                        didOpen(textDocument);
                    }
                    this._syncedDocuments.set(uri, textDocument);
                }
            });
        }
        notificationSent(any) {
            super.notificationSent(any);
            this._syncedDocuments.set(any.uri.toString(), any);
        }
    }
    class DidCloseTextDocumentFeature extends DocumentNotifiactions {
        constructor(client, _syncedDocuments) {
            super(client, exports.vscode.workspace.onDidCloseTextDocument, vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.type, client.clientOptions.middleware.didClose, (any) => client.code2ProtocolConverter.asCloseTextDocumentParams(any), DocumentNotifiactions.textDocumentFilter);
            this._syncedDocuments = _syncedDocuments;
        }
        get messages() {
            return vscode_languageserver_protocol_1.DidCloseTextDocumentNotification.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync;
            if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.openClose) {
                this.register(this.messages, { id: UUID.generateUuid(), registerOptions: { documentSelector: documentSelector } });
            }
        }
        notificationSent(any) {
            super.notificationSent(any);
            this._syncedDocuments.delete(any.uri.toString());
        }
        unregister(id) {
            let selector = this._selectors.get(id);
            // The super call removed the selector from the map
            // of selectors.
            super.unregister(id);
            let selectors = this._selectors.values();
            this._syncedDocuments.forEach((any) => {
                if (exports.vscode.languages.match(selector, any) && !this._selectorFilter(selectors, any)) {
                    let middleware = this._client.clientOptions.middleware;
                    let didClose = (any) => {
                        this._client.sendNotification(this._type, this._createParams(any));
                    };
                    this._syncedDocuments.delete(any.uri.toString());
                    if (middleware.didClose) {
                        middleware.didClose(any, didClose);
                    }
                    else {
                        didClose(any);
                    }
                }
            });
        }
    }
    class DidChangeTextDocumentFeature {
        constructor(_client) {
            this._client = _client;
            this._changeData = new Map();
            this._forcingDelivery = false;
        }
        get messages() {
            return vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'textDocument'), 'synchronization').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync;
            if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.change !== void 0 && textDocumentSyncOptions.change !== vscode_languageserver_protocol_1.TextDocumentSyncKind.None) {
                this.register(this.messages, {
                    id: UUID.generateUuid(),
                    registerOptions: Object.assign({}, { documentSelector: documentSelector }, { syncKind: textDocumentSyncOptions.change })
                });
            }
        }
        register(_message, data) {
            if (!data.registerOptions.documentSelector) {
                return;
            }
            if (!this._listener) {
                this._listener = exports.vscode.workspace.onDidChangeTextDocument(this.callback, this);
            }
            this._changeData.set(data.id, {
                documentSelector: data.registerOptions.documentSelector,
                syncKind: data.registerOptions.syncKind
            });
        }
        callback(event) {
            for (const changeData of this._changeData.values()) {
                if (exports.vscode.languages.match(changeData.documentSelector, event.document)) {
                    let middleware = this._client.clientOptions.middleware;
                    if (changeData.syncKind === vscode_languageserver_protocol_1.TextDocumentSyncKind.Incremental) {
                        let params = this._client.code2ProtocolConverter.asChangeTextDocumentParams(event);
                        if (middleware.didChange) {
                            middleware.didChange(event, () => this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params));
                        }
                        else {
                            this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, params);
                        }
                    }
                    else if (changeData.syncKind === vscode_languageserver_protocol_1.TextDocumentSyncKind.Full) {
                        let didChange = (event) => {
                            if (this._changeDelayer) {
                                if (this._changeDelayer.uri !== event.document.uri.toString()) {
                                    // Use this force delivery to track boolean state. Otherwise we might call two times.
                                    this.forceDelivery();
                                    this._changeDelayer.uri = event.document.uri.toString();
                                }
                                this._changeDelayer.delayer.trigger(() => {
                                    this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, this._client.code2ProtocolConverter.asChangeTextDocumentParams(event.document));
                                });
                            }
                            else {
                                this._changeDelayer = {
                                    uri: event.document.uri.toString(),
                                    delayer: new async_1.Delayer(200)
                                };
                                this._changeDelayer.delayer.trigger(() => {
                                    this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type, this._client.code2ProtocolConverter.asChangeTextDocumentParams(event.document));
                                }, -1);
                            }
                        };
                        if (middleware.didChange) {
                            middleware.didChange(event, didChange);
                        }
                        else {
                            didChange(event);
                        }
                    }
                }
            }
        }
        unregister(id) {
            this._changeData.delete(id);
            if (this._changeData.size === 0 && this._listener) {
                this._listener.dispose();
                this._listener = undefined;
            }
        }
        dispose() {
            if (this._listener) {
                this._listener.dispose();
                this._listener = undefined;
            }
        }
        forceDelivery() {
            if (this._forcingDelivery || !this._changeDelayer) {
                return;
            }
            try {
                this._forcingDelivery = true;
                this._changeDelayer.delayer.forceDelivery();
            }
            finally {
                this._forcingDelivery = false;
            }
        }
    }
    class WillSaveFeature extends DocumentNotifiactions {
        constructor(client) {
            super(client, exports.vscode.workspace.onWillSaveTextDocument, vscode_languageserver_protocol_1.WillSaveTextDocumentNotification.type, client.clientOptions.middleware.willSave, (willSaveEvent) => client.code2ProtocolConverter.asWillSaveTextDocumentParams(willSaveEvent), (selectors, willSaveEvent) => DocumentNotifiactions.textDocumentFilter(selectors, willSaveEvent.document));
        }
        get messages() {
            return vscode_languageserver_protocol_1.WillSaveTextDocumentNotification.type;
        }
        fillClientCapabilities(capabilities) {
            let value = ensure(ensure(capabilities, 'textDocument'), 'synchronization');
            value.willSave = true;
        }
        initialize(capabilities, documentSelector) {
            let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync;
            if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.willSave) {
                this.register(this.messages, {
                    id: UUID.generateUuid(),
                    registerOptions: { documentSelector: documentSelector }
                });
            }
        }
    }
    class WillSaveWaitUntilFeature {
        constructor(_client) {
            this._client = _client;
            this._selectors = new Map();
        }
        get messages() {
            return vscode_languageserver_protocol_1.WillSaveTextDocumentWaitUntilRequest.type;
        }
        fillClientCapabilities(capabilities) {
            let value = ensure(ensure(capabilities, 'textDocument'), 'synchronization');
            value.willSaveWaitUntil = true;
        }
        initialize(capabilities, documentSelector) {
            let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync;
            if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.willSaveWaitUntil) {
                this.register(this.messages, {
                    id: UUID.generateUuid(),
                    registerOptions: { documentSelector: documentSelector }
                });
            }
        }
        register(_message, data) {
            if (!data.registerOptions.documentSelector) {
                return;
            }
            if (!this._listener) {
                this._listener = exports.vscode.workspace.onWillSaveTextDocument(this.callback, this);
            }
            this._selectors.set(data.id, data.registerOptions.documentSelector);
        }
        callback(event) {
            if (DocumentNotifiactions.textDocumentFilter(this._selectors.values(), event.document)) {
                let middleware = this._client.clientOptions.middleware;
                let willSaveWaitUntil = (event) => {
                    return this._client.sendRequest(vscode_languageserver_protocol_1.WillSaveTextDocumentWaitUntilRequest.type, this._client.code2ProtocolConverter.asWillSaveTextDocumentParams(event)).then((edits) => {
                        let vEdits = this._client.protocol2CodeConverter.asTextEdits(edits);
                        return vEdits === void 0 ? [] : vEdits;
                    });
                };
                event.waitUntil(middleware.willSaveWaitUntil
                    ? middleware.willSaveWaitUntil(event, willSaveWaitUntil)
                    : willSaveWaitUntil(event));
            }
        }
        unregister(id) {
            this._selectors.delete(id);
            if (this._selectors.size === 0 && this._listener) {
                this._listener.dispose();
                this._listener = undefined;
            }
        }
        dispose() {
            if (this._listener) {
                this._listener.dispose();
                this._listener = undefined;
            }
        }
    }
    class DidSaveTextDocumentFeature extends DocumentNotifiactions {
        constructor(client) {
            super(client, exports.vscode.workspace.onDidSaveTextDocument, vscode_languageserver_protocol_1.DidSaveTextDocumentNotification.type, client.clientOptions.middleware.didSave, (any) => client.code2ProtocolConverter.asSaveTextDocumentParams(any, this._includeText), DocumentNotifiactions.textDocumentFilter);
        }
        get messages() {
            return vscode_languageserver_protocol_1.DidSaveTextDocumentNotification.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'textDocument'), 'synchronization').didSave = true;
        }
        initialize(capabilities, documentSelector) {
            let textDocumentSyncOptions = capabilities.resolvedTextDocumentSync;
            if (documentSelector && textDocumentSyncOptions && textDocumentSyncOptions.save) {
                this.register(this.messages, {
                    id: UUID.generateUuid(),
                    registerOptions: Object.assign({}, { documentSelector: documentSelector }, { includeText: !!textDocumentSyncOptions.save.includeText })
                });
            }
        }
        register(method, data) {
            this._includeText = !!data.registerOptions.includeText;
            super.register(method, data);
        }
    }
    class FileSystemWatcherFeature {
        constructor(_client, _notifyFileEvent) {
            this._client = _client;
            this._notifyFileEvent = _notifyFileEvent;
            this._watchers = new Map();
        }
        get messages() {
            return vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'workspace'), 'didChangeWatchedFiles').dynamicRegistration = true;
        }
        initialize(_capabilities, _documentSelector) {
        }
        register(_method, data) {
            if (!Array.isArray(data.registerOptions.watchers)) {
                return;
            }
            let disposeables = [];
            for (let watcher of data.registerOptions.watchers) {
                if (!Is.string(watcher.globPattern)) {
                    continue;
                }
                let watchCreate = true, watchChange = true, watchDelete = true;
                if (watcher.kind !== void 0 && watcher.kind !== null) {
                    watchCreate = (watcher.kind & vscode_languageserver_protocol_1.WatchKind.Create) !== 0;
                    watchChange = (watcher.kind & vscode_languageserver_protocol_1.WatchKind.Change) != 0;
                    watchDelete = (watcher.kind & vscode_languageserver_protocol_1.WatchKind.Delete) != 0;
                }
                let fileSystemWatcher = exports.vscode.workspace.createFileSystemWatcher(watcher.globPattern, !watchCreate, !watchChange, !watchDelete);
                this.hookListeners(fileSystemWatcher, watchCreate, watchChange, watchDelete);
                disposeables.push(fileSystemWatcher);
            }
            this._watchers.set(data.id, disposeables);
        }
        registerRaw(id, fileSystemWatchers) {
            let disposeables = [];
            for (let fileSystemWatcher of fileSystemWatchers) {
                this.hookListeners(fileSystemWatcher, true, true, true, disposeables);
            }
            this._watchers.set(id, disposeables);
        }
        hookListeners(fileSystemWatcher, watchCreate, watchChange, watchDelete, listeners) {
            if (watchCreate) {
                fileSystemWatcher.onDidCreate((resource) => this._notifyFileEvent({
                    uri: this._client.code2ProtocolConverter.asUri(resource),
                    type: vscode_languageserver_protocol_1.FileChangeType.Created
                }), null, listeners);
            }
            if (watchChange) {
                fileSystemWatcher.onDidChange((resource) => this._notifyFileEvent({
                    uri: this._client.code2ProtocolConverter.asUri(resource),
                    type: vscode_languageserver_protocol_1.FileChangeType.Changed
                }), null, listeners);
            }
            if (watchDelete) {
                fileSystemWatcher.onDidDelete((resource) => this._notifyFileEvent({
                    uri: this._client.code2ProtocolConverter.asUri(resource),
                    type: vscode_languageserver_protocol_1.FileChangeType.Deleted
                }), null, listeners);
            }
        }
        unregister(id) {
            let disposeables = this._watchers.get(id);
            if (disposeables) {
                for (let any of disposeables) {
                    any.dispose();
                }
            }
        }
        dispose() {
            this._watchers.forEach((disposeables) => {
                for (let any of disposeables) {
                    any.dispose();
                }
            });
        }
    }
    class TextDocumentFeature {
        constructor(_client, _message) {
            this._client = _client;
            this._message = _message;
            this._providers = new Map();
        }
        get messages() {
            return this._message;
        }
        register(message, data) {
            if (message.method !== this.messages.method) {
                throw new Error(`Register called on wrong feature. Requested ${message.method} but reached feature ${this.messages.method}`);
            }
            if (!data.registerOptions.documentSelector) {
                return;
            }
            let provider = this.registerLanguageProvider(data.registerOptions);
            if (provider) {
                this._providers.set(data.id, provider);
            }
        }
        unregister(id) {
            let provider = this._providers.get(id);
            if (provider) {
                provider.dispose();
            }
        }
        dispose() {
            this._providers.forEach((value) => {
                value.dispose();
            });
        }
    }
    exports.TextDocumentFeature = TextDocumentFeature;
    class WorkspaceFeature {
        constructor(_client, _message) {
            this._client = _client;
            this._message = _message;
            this._providers = new Map();
        }
        get messages() {
            return this._message;
        }
        register(message, data) {
            if (message.method !== this.messages.method) {
                throw new Error(`Register called on wron feature. Requested ${message.method} but reached feature ${this.messages.method}`);
            }
            let provider = this.registerLanguageProvider(data.registerOptions);
            if (provider) {
                this._providers.set(data.id, provider);
            }
        }
        unregister(id) {
            let provider = this._providers.get(id);
            if (provider) {
                provider.dispose();
            }
        }
        dispose() {
            this._providers.forEach((value) => {
                value.dispose();
            });
        }
    }
    class CompletionItemFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.CompletionRequest.type);
        }
        fillClientCapabilities(capabilites) {
            let completion = ensure(ensure(capabilites, 'textDocument'), 'completion');
            completion.dynamicRegistration = true;
            completion.contextSupport = true;
            completion.completionItem = { snippetSupport: true, commitCharactersSupport: true, documentationFormat: [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText] };
            completion.completionItemKind = { valueSet: SupportedCompletionItemKinds };
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.completionProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.completionProvider)
            });
        }
        registerLanguageProvider(options) {
            let triggerCharacters = options.triggerCharacters || [];
            let client = this._client;
            let provideCompletionItems = (document, position, context, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.CompletionRequest.type, client.code2ProtocolConverter.asCompletionParams(document, position, context), token).then(client.protocol2CodeConverter.asCompletionResult, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.CompletionRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let resolveCompletionItem = (item, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.CompletionResolveRequest.type, client.code2ProtocolConverter.asCompletionItem(item), token).then(client.protocol2CodeConverter.asCompletionItem, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.CompletionResolveRequest.type, error);
                    return Promise.resolve(item);
                });
            };
            let middleware = this._client.clientOptions.middleware;
            return exports.vscode.languages.registerCompletionItemProvider(options.documentSelector, {
                provideCompletionItems: (document, position, token, context) => {
                    return middleware.provideCompletionItem
                        ? middleware.provideCompletionItem(document, position, context, token, provideCompletionItems)
                        : provideCompletionItems(document, position, context, token);
                },
                resolveCompletionItem: options.resolveProvider
                    ? (item, token) => {
                        return middleware.resolveCompletionItem
                            ? middleware.resolveCompletionItem(item, token, resolveCompletionItem)
                            : resolveCompletionItem(item, token);
                    }
                    : undefined
            }, ...triggerCharacters);
        }
    }
    class HoverFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.HoverRequest.type);
        }
        fillClientCapabilities(capabilites) {
            const hoverCapability = (ensure(ensure(capabilites, 'textDocument'), 'hover'));
            hoverCapability.dynamicRegistration = true;
            hoverCapability.contentFormat = [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText];
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.hoverProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideHover = (document, position, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asHover, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.HoverRequest.type, error);
                    return Promise.resolve(null);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerHoverProvider(options.documentSelector, {
                provideHover: (document, position, token) => {
                    return middleware.provideHover
                        ? middleware.provideHover(document, position, token, provideHover)
                        : provideHover(document, position, token);
                }
            });
        }
    }
    class SignatureHelpFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.SignatureHelpRequest.type);
        }
        fillClientCapabilities(capabilites) {
            let config = ensure(ensure(capabilites, 'textDocument'), 'signatureHelp');
            config.dynamicRegistration = true;
            config.signatureInformation = { documentationFormat: [vscode_languageserver_protocol_1.MarkupKind.Markdown, vscode_languageserver_protocol_1.MarkupKind.PlainText] };
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.signatureHelpProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.signatureHelpProvider)
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let providerSignatureHelp = (document, position, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.SignatureHelpRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asSignatureHelp, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.SignatureHelpRequest.type, error);
                    return Promise.resolve(null);
                });
            };
            let middleware = client.clientOptions.middleware;
            let triggerCharacters = options.triggerCharacters || [];
            return exports.vscode.languages.registerSignatureHelpProvider(options.documentSelector, {
                provideSignatureHelp: (document, position, token) => {
                    return middleware.provideSignatureHelp
                        ? middleware.provideSignatureHelp(document, position, token, providerSignatureHelp)
                        : providerSignatureHelp(document, position, token);
                }
            }, ...triggerCharacters);
        }
    }
    class DefinitionFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DefinitionRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'definition').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.definitionProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideDefinition = (document, position, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asDefinitionResult, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, error);
                    return Promise.resolve(null);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerDefinitionProvider(options.documentSelector, {
                provideDefinition: (document, position, token) => {
                    return middleware.provideDefinition
                        ? middleware.provideDefinition(document, position, token, provideDefinition)
                        : provideDefinition(document, position, token);
                }
            });
        }
    }
    class ReferencesFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.ReferencesRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'references').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.referencesProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let providerReferences = (document, position, options, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.ReferencesRequest.type, client.code2ProtocolConverter.asReferenceParams(document, position, options), token).then(client.protocol2CodeConverter.asReferences, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.ReferencesRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerReferenceProvider(options.documentSelector, {
                provideReferences: (document, position, options, token) => {
                    return middleware.provideReferences
                        ? middleware.provideReferences(document, position, options, token, providerReferences)
                        : providerReferences(document, position, options, token);
                }
            });
        }
    }
    class DocumentHighlightFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DocumentHighlightRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'documentHighlight').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.documentHighlightProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideDocumentHighlights = (document, position, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentHighlightRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then(client.protocol2CodeConverter.asDocumentHighlights, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentHighlightRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerDocumentHighlightProvider(options.documentSelector, {
                provideDocumentHighlights: (document, position, token) => {
                    return middleware.provideDocumentHighlights
                        ? middleware.provideDocumentHighlights(document, position, token, provideDocumentHighlights)
                        : provideDocumentHighlights(document, position, token);
                }
            });
        }
    }
    class DocumentSymbolFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DocumentSymbolRequest.type);
        }
        fillClientCapabilities(capabilites) {
            let symbolCapabilities = ensure(ensure(capabilites, 'textDocument'), 'documentSymbol');
            symbolCapabilities.dynamicRegistration = true;
            symbolCapabilities.symbolKind = {
                valueSet: SupporedSymbolKinds
            };
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.documentSymbolProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideDocumentSymbols = (document, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentSymbolRequest.type, client.code2ProtocolConverter.asDocumentSymbolParams(document), token).then(client.protocol2CodeConverter.asSymbolInformations, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentSymbolRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerDocumentSymbolProvider(options.documentSelector, {
                provideDocumentSymbols: (document, token) => {
                    return middleware.provideDocumentSymbols
                        ? middleware.provideDocumentSymbols(document, token, provideDocumentSymbols)
                        : provideDocumentSymbols(document, token);
                }
            });
        }
    }
    class WorkspaceSymbolFeature extends WorkspaceFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type);
        }
        fillClientCapabilities(capabilites) {
            let symbolCapabilities = ensure(ensure(capabilites, 'workspace'), 'symbol');
            symbolCapabilities.dynamicRegistration = true;
            symbolCapabilities.symbolKind = {
                valueSet: SupporedSymbolKinds
            };
        }
        initialize(capabilities) {
            if (!capabilities.workspaceSymbolProvider) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: undefined
            });
        }
        registerLanguageProvider(_options) {
            let client = this._client;
            let provideWorkspaceSymbols = (query, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type, { query }, token).then(client.protocol2CodeConverter.asSymbolInformations, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.WorkspaceSymbolRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerWorkspaceSymbolProvider({
                provideWorkspaceSymbols: (query, token) => {
                    return middleware.provideWorkspaceSymbols
                        ? middleware.provideWorkspaceSymbols(query, token, provideWorkspaceSymbols)
                        : provideWorkspaceSymbols(query, token);
                }
            });
        }
    }
    class CodeActionFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.CodeActionRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'codeAction').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.codeActionProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideCodeActions = (document, range, context, token) => {
                let params = {
                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
                    range: client.code2ProtocolConverter.asRange(range),
                    context: client.code2ProtocolConverter.asCodeActionContext(context)
                };
                return client.sendRequest(vscode_languageserver_protocol_1.CodeActionRequest.type, params, token).then(client.protocol2CodeConverter.asCommands, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.CodeActionRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerCodeActionsProvider(options.documentSelector, {
                provideCodeActions: (document, range, context, token) => {
                    return middleware.provideCodeActions
                        ? middleware.provideCodeActions(document, range, context, token, provideCodeActions)
                        : provideCodeActions(document, range, context, token);
                }
            });
        }
    }
    class CodeLensFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.CodeLensRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'codeLens').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.codeLensProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.codeLensProvider)
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideCodeLenses = (document, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.CodeLensRequest.type, client.code2ProtocolConverter.asCodeLensParams(document), token).then(client.protocol2CodeConverter.asCodeLenses, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.CodeLensRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let resolveCodeLens = (codeLens, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.CodeLensResolveRequest.type, client.code2ProtocolConverter.asCodeLens(codeLens), token).then(client.protocol2CodeConverter.asCodeLens, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.CodeLensResolveRequest.type, error);
                    return codeLens;
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerCodeLensProvider(options.documentSelector, {
                provideCodeLenses: (document, token) => {
                    return middleware.provideCodeLenses
                        ? middleware.provideCodeLenses(document, token, provideCodeLenses)
                        : provideCodeLenses(document, token);
                },
                resolveCodeLens: (options.resolveProvider)
                    ? (codeLens, token) => {
                        return middleware.resolveCodeLens
                            ? middleware.resolveCodeLens(codeLens, token, resolveCodeLens)
                            : resolveCodeLens(codeLens, token);
                    }
                    : undefined
            });
        }
    }
    class DocumentFormattingFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DocumentFormattingRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'formatting').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.documentFormattingProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideDocumentFormattingEdits = (document, options, token) => {
                let params = {
                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
                    options: client.code2ProtocolConverter.asFormattingOptions(options)
                };
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentFormattingRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerDocumentFormattingEditProvider(options.documentSelector, {
                provideDocumentFormattingEdits: (document, options, token) => {
                    return middleware.provideDocumentFormattingEdits
                        ? middleware.provideDocumentFormattingEdits(document, options, token, provideDocumentFormattingEdits)
                        : provideDocumentFormattingEdits(document, options, token);
                }
            });
        }
    }
    class DocumentRangeFormattingFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'rangeFormatting').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.documentRangeFormattingProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideDocumentRangeFormattingEdits = (document, range, options, token) => {
                let params = {
                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
                    range: client.code2ProtocolConverter.asRange(range),
                    options: client.code2ProtocolConverter.asFormattingOptions(options)
                };
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentRangeFormattingRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerDocumentRangeFormattingEditProvider(options.documentSelector, {
                provideDocumentRangeFormattingEdits: (document, range, options, token) => {
                    return middleware.provideDocumentRangeFormattingEdits
                        ? middleware.provideDocumentRangeFormattingEdits(document, range, options, token, provideDocumentRangeFormattingEdits)
                        : provideDocumentRangeFormattingEdits(document, range, options, token);
                }
            });
        }
    }
    class DocumentOnTypeFormattingFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'onTypeFormatting').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.documentOnTypeFormattingProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.documentOnTypeFormattingProvider)
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let moreTriggerCharacter = options.moreTriggerCharacter || [];
            let provideOnTypeFormattingEdits = (document, position, ch, options, token) => {
                let params = {
                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
                    position: client.code2ProtocolConverter.asPosition(position),
                    ch: ch,
                    options: client.code2ProtocolConverter.asFormattingOptions(options)
                };
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type, params, token).then(client.protocol2CodeConverter.asTextEdits, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentOnTypeFormattingRequest.type, error);
                    return Promise.resolve([]);
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerOnTypeFormattingEditProvider(options.documentSelector, {
                provideOnTypeFormattingEdits: (document, position, ch, options, token) => {
                    return middleware.provideOnTypeFormattingEdits
                        ? middleware.provideOnTypeFormattingEdits(document, position, ch, options, token, provideOnTypeFormattingEdits)
                        : provideOnTypeFormattingEdits(document, position, ch, options, token);
                }
            }, options.firstTriggerCharacter, ...moreTriggerCharacter);
        }
    }
    class RenameFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.RenameRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'rename').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.renameProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector })
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideRenameEdits = (document, position, newName, token) => {
                let params = {
                    textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document),
                    position: client.code2ProtocolConverter.asPosition(position),
                    newName: newName
                };
                return client.sendRequest(vscode_languageserver_protocol_1.RenameRequest.type, params, token).then(client.protocol2CodeConverter.asWorkspaceEdit, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.RenameRequest.type, error);
                    return Promise.reject(new Error(error.message));
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerRenameProvider(options.documentSelector, {
                provideRenameEdits: (document, position, newName, token) => {
                    return middleware.provideRenameEdits
                        ? middleware.provideRenameEdits(document, position, newName, token, provideRenameEdits)
                        : provideRenameEdits(document, position, newName, token);
                }
            });
        }
    }
    class DocumentLinkFeature extends TextDocumentFeature {
        constructor(client) {
            super(client, vscode_languageserver_protocol_1.DocumentLinkRequest.type);
        }
        fillClientCapabilities(capabilites) {
            ensure(ensure(capabilites, 'textDocument'), 'documentLink').dynamicRegistration = true;
        }
        initialize(capabilities, documentSelector) {
            if (!capabilities.documentLinkProvider || !documentSelector) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, { documentSelector: documentSelector }, capabilities.documentLinkProvider)
            });
        }
        registerLanguageProvider(options) {
            let client = this._client;
            let provideDocumentLinks = (document, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentLinkRequest.type, client.code2ProtocolConverter.asDocumentLinkParams(document), token).then(client.protocol2CodeConverter.asDocumentLinks, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentLinkRequest.type, error);
                    Promise.resolve(new Error(error.message));
                });
            };
            let resolveDocumentLink = (link, token) => {
                return client.sendRequest(vscode_languageserver_protocol_1.DocumentLinkResolveRequest.type, client.code2ProtocolConverter.asDocumentLink(link), token).then(client.protocol2CodeConverter.asDocumentLink, (error) => {
                    client.logFailedRequest(vscode_languageserver_protocol_1.DocumentLinkResolveRequest.type, error);
                    Promise.resolve(new Error(error.message));
                });
            };
            let middleware = client.clientOptions.middleware;
            return exports.vscode.languages.registerDocumentLinkProvider(options.documentSelector, {
                provideDocumentLinks: (document, token) => {
                    return middleware.provideDocumentLinks
                        ? middleware.provideDocumentLinks(document, token, provideDocumentLinks)
                        : provideDocumentLinks(document, token);
                },
                resolveDocumentLink: options.resolveProvider
                    ? (link, token) => {
                        return middleware.resolveDocumentLink
                            ? middleware.resolveDocumentLink(link, token, resolveDocumentLink)
                            : resolveDocumentLink(link, token);
                    }
                    : undefined
            });
        }
    }
    class ConfigurationFeature {
        constructor(_client) {
            this._client = _client;
            this._listeners = new Map();
        }
        get messages() {
            return vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'workspace'), 'didChangeConfiguration').dynamicRegistration = true;
        }
        initialize() {
            let section = this._client.clientOptions.synchronize.configurationSection;
            if (section !== void 0) {
                this.register(this.messages, {
                    id: UUID.generateUuid(),
                    registerOptions: {
                        section: section
                    }
                });
            }
        }
        register(_message, data) {
            let any = exports.vscode.workspace.onDidChangeConfiguration(() => {
                this.onDidChangeConfiguration(data.registerOptions.section);
            });
            this._listeners.set(data.id, any);
            if (data.registerOptions.section !== void 0) {
                this.onDidChangeConfiguration(data.registerOptions.section);
            }
        }
        unregister(id) {
            let any = this._listeners.get(id);
            if (any) {
                this._listeners.delete(id);
                any.dispose();
            }
        }
        dispose() {
            for (let any of this._listeners.values()) {
                any.dispose();
            }
        }
        onDidChangeConfiguration(configurationSection) {
            let sections;
            if (Is.string(configurationSection)) {
                sections = [configurationSection];
            }
            else {
                sections = configurationSection;
            }
            let didChangeConfiguration = (sections) => {
                if (sections === void 0) {
                    this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type, { settings: null });
                    return;
                }
                this._client.sendNotification(vscode_languageserver_protocol_1.DidChangeConfigurationNotification.type, { settings: this.extractSettingsInformation(sections) });
            };
            let middleware = this.getMiddleware();
            middleware
                ? middleware(sections, didChangeConfiguration)
                : didChangeConfiguration(sections);
        }
        extractSettingsInformation(keys) {
            function ensurePath(config, path) {
                let current = config;
                for (let i = 0; i < path.length - 1; i++) {
                    let obj = current[path[i]];
                    if (!obj) {
                        obj = Object.create(null);
                        current[path[i]] = obj;
                    }
                    current = obj;
                }
                return current;
            }
            let resource = this._client.clientOptions.workspaceFolder
                ? this._client.clientOptions.workspaceFolder.uri
                : undefined;
            let result = Object.create(null);
            for (let i = 0; i < keys.length; i++) {
                let key = keys[i];
                let index = key.indexOf('.');
                let config = null;
                if (index >= 0) {
                    config = exports.vscode.workspace.getConfiguration(key.substr(0, index), resource).get(key.substr(index + 1));
                }
                else {
                    config = exports.vscode.workspace.getConfiguration(key, resource);
                }
                if (config) {
                    let path = keys[i].split('.');
                    ensurePath(result, path)[path[path.length - 1]] = config;
                }
            }
            return result;
        }
        getMiddleware() {
            let middleware = this._client.clientOptions.middleware;
            if (middleware.Workspace && middleware.Workspace.didChangeConfiguration) {
                return middleware.Workspace.didChangeConfiguration;
            }
            else {
                return undefined;
            }
        }
    }
    class ExecuteCommandFeature {
        constructor(_client) {
            this._client = _client;
            this._commands = new Map();
        }
        get messages() {
            return vscode_languageserver_protocol_1.ExecuteCommandRequest.type;
        }
        fillClientCapabilities(capabilities) {
            ensure(ensure(capabilities, 'workspace'), 'executeCommand').dynamicRegistration = true;
        }
        initialize(capabilities) {
            if (!capabilities.executeCommandProvider) {
                return;
            }
            this.register(this.messages, {
                id: UUID.generateUuid(),
                registerOptions: Object.assign({}, capabilities.executeCommandProvider)
            });
        }
        register(_message, data) {
            let client = this._client;
            if (data.registerOptions.commands) {
                let disposeables = [];
                for (const command of data.registerOptions.commands) {
                    disposeables.push(exports.vscode.Commands.registerCommand(command, (...args) => {
                        let params = {
                            command,
                            arguments: args
                        };
                        return client.sendRequest(vscode_languageserver_protocol_1.ExecuteCommandRequest.type, params).then(undefined, (error) => {
                            client.logFailedRequest(vscode_languageserver_protocol_1.ExecuteCommandRequest.type, error);
                        });
                    }));
                }
                this._commands.set(data.id, disposeables);
            }
        }
        unregister(id) {
            let disposeables = this._commands.get(id);
            if (disposeables) {
                disposeables.forEach(any => any.dispose());
            }
        }
        dispose() {
            this._commands.forEach((value) => {
                value.forEach(any => any.dispose());
            });
        }
    }
    var MessageTransports;
    (function (MessageTransports) {
        function is(value) {
            let candidate = value;
            return candidate && vscode_languageserver_protocol_1.MessageReader.is(value.reader) && vscode_languageserver_protocol_1.MessageWriter.is(value.writer);
        }
        MessageTransports.is = is;
    })(MessageTransports = exports.MessageTransports || (exports.MessageTransports = {}));
    class BaseLanguageClient {
        constructor(id, name, clientOptions) {
            this._requests = new Map();
            this._features = [];
            this._method2Message = new Map();
            this._dynamicFeatures = new Map();
            exports.vscode = clientOptions.vscode;
            this._id = id;
            this._name = name;
            clientOptions = clientOptions || {};
            this._clientOptions = {
                documentSelector: clientOptions.documentSelector || [],
                synchronize: clientOptions.synchronize || {},
                diagnosticCollectionName: clientOptions.diagnosticCollectionName,
                outputChannelName: clientOptions.outputChannelName || this._name,
                revealOutputChannelOn: clientOptions.revealOutputChannelOn || RevealOutputChannelOn.Error,
                stdioEncoding: clientOptions.stdioEncoding || 'utf8',
                initializationOptions: clientOptions.initializationOptions,
                initializationFailedHandler: clientOptions.initializationFailedHandler,
                errorHandler: clientOptions.errorHandler || new DefaultErrorHandler(this._name),
                middleware: clientOptions.middleware || {},
                uriConverters: clientOptions.uriConverters,
                workspaceFolder: clientOptions.workspaceFolder,
                vscode: clientOptions.vscode
            };
            this._clientOptions.synchronize = this._clientOptions.synchronize || {};
            this.state = ClientState.Initial;
            this._initializeResult = undefined;
            if (clientOptions.any) {
                this._outputChannel = clientOptions.any;
            }
            else {
                this._outputChannel = undefined;
            }
            this._diagnostics = undefined;
            this._fileEvents = [];
            this._fileEventDelayer = new async_1.Delayer(250);
            this._onReady = new Promise((resolve, reject) => {
                this._onReadyCallbacks = { resolve, reject };
            });
            this._telemetryEmitter = new vscode_languageserver_protocol_1.Emitter();
            this._stateChangeEmitter = new vscode_languageserver_protocol_1.Emitter();
            this._c2p = c2p.createConverter(exports.vscode, clientOptions.uriConverters ? clientOptions.uriConverters.code2Protocol : undefined);
            this._p2c = p2c.createConverter(exports.vscode, clientOptions.uriConverters ? clientOptions.uriConverters.protocol2Code : undefined);
            this._syncedDocuments = new Map();
            this.registerBuiltinFeatures();
        }
        get state() {
            return this._state;
        }
        set state(value) {
            let oldState = this.getPublicState();
            this._state = value;
            let newState = this.getPublicState();
            if (newState !== oldState) {
                this._stateChangeEmitter.fire({ oldState, newState });
            }
        }
        getPublicState() {
            if (this.state === ClientState.Running) {
                return State.Running;
            }
            else {
                return State.Stopped;
            }
        }
        get initializeResult() {
            return this._initializeResult;
        }
        sendRequest(type, ...params) {
            if (!this.isConnectionActive()) {
                throw new Error('Language client is not ready yet');
            }
            this.forceDocumentSync();
            try {
                var eventName = "";
                if (!Is.string(type)) {
                    eventName = type.method;
                }
                else {
                    eventName = type.toString();
                }
                var uuid = UUID.generateUuid();
                return new Promise((resolve, reject) => {
                    //this._requests.set("request_" + eventName + "_" + uuid, resolve);
                    var ev = new CustomEvent(this._id + "_request_" + eventName, {
                        detail: {
                            uuid: uuid,
                            params,
                            resolver: resolve,
                            rejecter: reject
                        }
                    });
                    window.dispatchEvent(ev);
                });
                //return this._resolvedConnection!.sendRequest<R>(type, ...params);
            }
            catch (error) {
                this.error(`Sending request ${Is.string(type) ? type : type} failed.`, error);
                throw error;
            }
        }
        onRequest(type, handler) {
            if (!this.isConnectionActive()) {
                throw new Error('Language client is not ready yet');
            }
            try {
                var eventName = "";
                if (!Is.string(type)) {
                    eventName = type.method;
                }
                else {
                    eventName = type.toString();
                }
                window.addEventListener(this._id + "_request_" + eventName, {
                    handleEvent: (customEvent) => {
                        var uuid = customEvent.detail.uuid;
                        var result = handler(customEvent.detail.params);
                        var cb = this._requests.get(customEvent.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete("request_" + eventName + "_" + uuid);
                    }
                });
                //this._resolvedConnection!.onRequest(type, handler);
            }
            catch (error) {
                this.error(`Registering request handler ${Is.string(type) ? type : type.method} failed.`, error);
                throw error;
            }
        }
        sendNotification(type, params) {
            if (!this.isConnectionActive()) {
                throw new Error('Language client is not ready yet');
            }
            this.forceDocumentSync();
            try {
                var eventName = "";
                if (!Is.string(type)) {
                    eventName = type.method;
                }
                else {
                    eventName = type.toString();
                }
                var ev = new CustomEvent(this._id + "_notify_" + eventName, {
                    detail: params
                });
                window.dispatchEvent(ev);
                //this._resolvedConnection!.sendNotification(type, params);
            }
            catch (error) {
                this.error(`Sending notification ${Is.string(type) ? type : type.method} failed.`, error);
                throw error;
            }
        }
        onNotification(type, handler) {
            if (!this.isConnectionActive()) {
                throw new Error('Language client is not ready yet');
            }
            try {
                var eventName = "";
                if (!Is.string(type)) {
                    eventName = type.method;
                }
                else {
                    eventName = type.toString();
                }
                window.addEventListener(this._id + "_nofity_" + eventName, {
                    handleEvent: (customEvent) => {
                        handler(customEvent.detail);
                    }
                });
                //this._resolvedConnection!.onNotification(type, handler);
            }
            catch (error) {
                this.error(`Registering notification handler ${Is.string(type) ? type : type.method} failed.`, error);
                throw error;
            }
        }
        get clientOptions() {
            return this._clientOptions;
        }
        get protocol2CodeConverter() {
            return this._p2c;
        }
        get code2ProtocolConverter() {
            return this._c2p;
        }
        get onTelemetry() {
            return this._telemetryEmitter.event;
        }
        get onDidChangeState() {
            return this._stateChangeEmitter.event;
        }
        get any() {
            if (!this._outputChannel) {
                this._outputChannel = exports.vscode.Window.createOutputChannel(this._clientOptions.outputChannelName ? this._clientOptions.outputChannelName : this._name);
            }
            return this._outputChannel;
        }
        get diagnostics() {
            return this._diagnostics;
        }
        createDefaultErrorHandler() {
            return new DefaultErrorHandler(this._name);
        }
        set trace(value) {
            this._trace = value;
        }
        data2String(data) {
            if (data instanceof vscode_languageserver_protocol_1.ResponseError) {
                const responseError = data;
                return `  Message: ${responseError.message}\n  Code: ${responseError.code} ${responseError.data ? '\n' + responseError.data.toString() : ''}`;
            }
            if (data instanceof Error) {
                if (Is.string(data.stack)) {
                    return data.stack;
                }
                return data.message;
            }
            if (Is.string(data)) {
                return data;
            }
            return data.toString();
        }
        info(message, data) {
            this.any.appendLine(`[Info  - ${(new Date().toLocaleTimeString())}] ${message}`);
            if (data) {
                this.any.appendLine(this.data2String(data));
            }
            if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Info) {
                this.any.show(true);
            }
        }
        warn(message, data) {
            this.any.appendLine(`[Warn  - ${(new Date().toLocaleTimeString())}] ${message}`);
            if (data) {
                this.any.appendLine(this.data2String(data));
            }
            if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Warn) {
                this.any.show(true);
            }
        }
        error(message, data) {
            this.any.appendLine(`[Error - ${(new Date().toLocaleTimeString())}] ${message}`);
            if (data) {
                this.any.appendLine(this.data2String(data));
            }
            if (this._clientOptions.revealOutputChannelOn <= RevealOutputChannelOn.Error) {
                this.any.show(true);
            }
        }
        needsStart() {
            return this.state === ClientState.Initial || this.state === ClientState.Stopping || this.state === ClientState.Stopped;
        }
        needsStop() {
            return this.state === ClientState.Starting || this.state === ClientState.Running;
        }
        onReady() {
            return this._onReady;
        }
        isConnectionActive() {
            return this.state === ClientState.Running; // && !!this._resolvedConnection;
        }
        start() {
            // If we restart then the diagnostics collection is reused.
            if (!this._diagnostics) {
                this._diagnostics = this._clientOptions.diagnosticCollectionName
                    ? exports.vscode.languages.createDiagnosticCollection(this._clientOptions.diagnosticCollectionName)
                    : exports.vscode.languages.createDiagnosticCollection();
            }
            this.state = ClientState.Starting;
            this.initialize();
            return {
                requests: this._requests
            };
        }
        initialize() {
            this.refreshTrace();
            let initOption = this._clientOptions.initializationOptions;
            let rootPath = this._clientOptions.workspaceFolder
                ? this._clientOptions.workspaceFolder.uri.fsPath
                : this._clientGetRootPath();
            let initParams = {
                processId: 1,
                rootPath: rootPath ? rootPath : null,
                rootUri: rootPath ? this._c2p.asUri(exports.vscode.Uri.file(rootPath)) : null,
                capabilities: this.computeClientCapabilities(),
                initializationOptions: Is.func(initOption) ? initOption() : initOption,
                trace: vscode_languageserver_protocol_1.Trace.toString(this._trace),
                workspaceFolders: null
            };
            this.fillInitializeParams(initParams);
            var uuid = UUID.generateUuid();
            return new Promise((resolve) => {
                this._requests.set(this._id + "_request_initialize_" + uuid, resolve);
                var ev = new CustomEvent(this._id + "_request_initialize", {
                    detail: {
                        uuid: uuid,
                        params: initParams,
                        requests: this._requests
                    }
                });
                window.dispatchEvent(ev);
            }).then((result) => {
                //this._resolvedConnection = connection;
                this._initializeResult = result;
                this.state = ClientState.Running;
                let textDocumentSyncOptions = undefined;
                if (Is.number(result.capabilities.textDocumentSync) && result.capabilities.textDocumentSync !== vscode_languageserver_protocol_1.TextDocumentSyncKind.None) {
                    textDocumentSyncOptions = {
                        openClose: true,
                        change: result.capabilities.textDocumentSync,
                        save: {
                            includeText: false
                        }
                    };
                }
                else if (result.capabilities.textDocumentSync !== void 0 && result.capabilities.textDocumentSync !== null) {
                    textDocumentSyncOptions = result.capabilities.textDocumentSync;
                }
                this._capabilities = Object.assign({}, result.capabilities, { resolvedTextDocumentSync: textDocumentSyncOptions });
                window.addEventListener(this._id + "_ondiagnostics", {
                    handleEvent: (ev) => {
                        var uuid = ev.detail.uuid;
                        var result = this.handleDiagnostics(ev.detail.params);
                        var cb = this._requests.get(ev.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete(ev.type + "_" + uuid);
                    }
                });
                window.addEventListener(this._id + "_client/registerCapability", {
                    handleEvent: (ev) => {
                        var uuid = ev.detail.uuid;
                        var result = this.handleRegistrationRequest(ev.detail.params);
                        var cb = this._requests.get(ev.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete(ev.type + "_" + uuid);
                    }
                });
                window.addEventListener(this._id + "_client/registerFeature", {
                    handleEvent: (ev) => {
                        var uuid = ev.detail.uuid;
                        var result = this.handleRegistrationRequest(ev.detail.params);
                        var cb = this._requests.get(ev.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete(ev.type + "_" + uuid);
                    }
                });
                window.addEventListener(this._id + "_client/unregisterCapability", {
                    handleEvent: (ev) => {
                        var uuid = ev.detail.uuid;
                        var result = this.handleUnregistrationRequest(ev.detail.params);
                        var cb = this._requests.get(ev.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete(ev.type + "_" + uuid);
                    }
                });
                window.addEventListener(this._id + "_client/unregisterFeature", {
                    handleEvent: (ev) => {
                        var uuid = ev.detail.uuid;
                        var result = this.handleUnregistrationRequest(ev.detail.params);
                        var cb = this._requests.get(ev.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete(ev.type + "_" + uuid);
                    }
                });
                window.addEventListener(this._id + "_vscode.Workspace/applyEdit", {
                    handleEvent: (ev) => {
                        var uuid = ev.detail.uuid;
                        var result = this.handleApplyWorkspaceEdit(ev.detail.params);
                        var cb = this._requests.get(ev.type + "_" + uuid);
                        cb && cb(result);
                        this._requests.delete(ev.type + "_" + uuid);
                    }
                });
                //connection.onDiagnostics(params => this.handleDiagnostics(params));
                //connection.onRequest(RegistrationRequest.type, params => this.handleRegistrationRequest(params));
                // See https://github.com/Microsoft/vscode-languageserver-node/issues/199
                //connection.onRequest('client/registerFeature', params => this.handleRegistrationRequest(params));
                //connection.onRequest(UnregistrationRequest.type, params => this.handleUnregistrationRequest(params));
                // See https://github.com/Microsoft/vscode-languageserver-node/issues/199
                //connection.onRequest('client/unregisterFeature', params => this.handleUnregistrationRequest(params));
                //connection.onRequest(ApplyWorkspaceEditRequest.type, params => this.handleApplyWorkspaceEdit(params));
                this._requests.set(this._id + "_notify_initialized" + uuid, () => { });
                var ev = new CustomEvent(this._id + "_notify_initialized" + uuid, {
                    detail: {
                        uuid: uuid,
                        params: {}
                    }
                });
                window.dispatchEvent(ev);
                //connection.sendNotification(InitializedNotification.type, {});
                this.hookFileEvents();
                this.hookConfigurationChanged();
                this.initializeFeatures();
                this._onReadyCallbacks.resolve();
                return result;
            }).then(undefined, (error) => {
                if (this._clientOptions.initializationFailedHandler) {
                    if (this._clientOptions.initializationFailedHandler(error)) {
                        this.initialize();
                    }
                    else {
                        this._onReadyCallbacks.reject(error);
                    }
                }
                else if (error instanceof vscode_languageserver_protocol_1.ResponseError && error.data && error.data.retry) {
                    exports.vscode.Window.showErrorMessage(error.message, { title: 'Retry', id: "retry" }).then((item) => {
                        if (item && item.id === 'retry') {
                            this.initialize();
                        }
                        else {
                            this._onReadyCallbacks.reject(error);
                        }
                    });
                }
                else {
                    if (error && error.message) {
                        exports.vscode.Window.showErrorMessage(error.message);
                    }
                    this.error('Server initialization failed.', error);
                    this._onReadyCallbacks.reject(error);
                }
                return Promise.reject(null);
            });
        }
        _clientGetRootPath() {
            let folders = exports.vscode.workspace.workspaceFolders;
            if (!folders || folders.length === 0) {
                return undefined;
            }
            let folder = folders[0];
            if (folder.uri.scheme === 'file') {
                return folder.uri.fsPath;
            }
            return undefined;
        }
        notifyFileEvent(event) {
            this._fileEvents.push(event);
            this._fileEventDelayer.trigger(() => {
                this.onReady().then(() => {
                    this.sendNotification(vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type, { changes: this._fileEvents });
                    this._fileEvents = [];
                }, (error) => {
                    this.error(`Notify file events failed.`, error);
                });
            });
        }
        forceDocumentSync() {
            this._dynamicFeatures.get(vscode_languageserver_protocol_1.DidChangeTextDocumentNotification.type.method).forceDelivery();
        }
        handleDiagnostics(params) {
            if (!this._diagnostics) {
                return;
            }
            let uri = this._p2c.asUri(params.uri);
            let diagnostics = this._p2c.asDiagnostics(params.diagnostics);
            let middleware = this.clientOptions.middleware.handleDiagnostics;
            if (middleware) {
                middleware(uri, diagnostics, (uri, diagnostics) => this.setDiagnostics(uri, diagnostics));
            }
            else {
                this.setDiagnostics(uri, diagnostics);
            }
        }
        setDiagnostics(uri, diagnostics) {
            if (!this._diagnostics) {
                return;
            }
            this._diagnostics.set(uri, diagnostics);
        }
        hookConfigurationChanged() {
            exports.vscode.workspace.onDidChangeConfiguration(() => {
            });
        }
        refreshTrace() {
            let config = exports.vscode.workspace.getConfiguration(this._id);
            let trace = vscode_languageserver_protocol_1.Trace.Off;
            if (config) {
                trace = vscode_languageserver_protocol_1.Trace.fromString(config.get('trace.server', 'off'));
            }
            this._trace = trace;
        }
        hookFileEvents() {
            let fileEvents = this._clientOptions.synchronize.fileEvents;
            if (!fileEvents) {
                return;
            }
            let watchers;
            if (Is.array(fileEvents)) {
                watchers = fileEvents;
            }
            else {
                watchers = [fileEvents];
            }
            if (!watchers) {
                return;
            }
            this._dynamicFeatures.get(vscode_languageserver_protocol_1.DidChangeWatchedFilesNotification.type.method).registerRaw(UUID.generateUuid(), watchers);
        }
        registerFeatures(features) {
            for (let feature of features) {
                this.registerFeature(feature);
            }
        }
        registerFeature(feature) {
            this._features.push(feature);
            if (DynamicFeature.is(feature)) {
                let messages = feature.messages;
                if (Array.isArray(messages)) {
                    for (let message of messages) {
                        this._method2Message.set(message.method, message);
                        this._dynamicFeatures.set(message.method, feature);
                    }
                }
                else {
                    this._method2Message.set(messages.method, messages);
                    this._dynamicFeatures.set(messages.method, feature);
                }
            }
        }
        registerBuiltinFeatures() {
            this.registerFeature(new ConfigurationFeature(this));
            this.registerFeature(new DidOpenTextDocumentFeature(this, this._syncedDocuments));
            this.registerFeature(new DidChangeTextDocumentFeature(this));
            this.registerFeature(new WillSaveFeature(this));
            this.registerFeature(new WillSaveWaitUntilFeature(this));
            this.registerFeature(new DidSaveTextDocumentFeature(this));
            this.registerFeature(new DidCloseTextDocumentFeature(this, this._syncedDocuments));
            this.registerFeature(new FileSystemWatcherFeature(this, (event) => this.notifyFileEvent(event)));
            this.registerFeature(new CompletionItemFeature(this));
            this.registerFeature(new HoverFeature(this));
            this.registerFeature(new SignatureHelpFeature(this));
            this.registerFeature(new DefinitionFeature(this));
            this.registerFeature(new ReferencesFeature(this));
            this.registerFeature(new DocumentHighlightFeature(this));
            this.registerFeature(new DocumentSymbolFeature(this));
            this.registerFeature(new WorkspaceSymbolFeature(this));
            this.registerFeature(new CodeActionFeature(this));
            this.registerFeature(new CodeLensFeature(this));
            this.registerFeature(new DocumentFormattingFeature(this));
            this.registerFeature(new DocumentRangeFormattingFeature(this));
            this.registerFeature(new DocumentOnTypeFormattingFeature(this));
            this.registerFeature(new RenameFeature(this));
            this.registerFeature(new DocumentLinkFeature(this));
            this.registerFeature(new ExecuteCommandFeature(this));
        }
        fillInitializeParams(params) {
            for (let feature of this._features) {
                if (Is.func(feature.fillInitializeParams)) {
                    feature.fillInitializeParams(params);
                }
            }
        }
        computeClientCapabilities() {
            let result = {};
            ensure(result, 'workspace').applyEdit = true;
            ensure(ensure(result, 'workspace'), 'workspaceEdit').documentChanges = true;
            ensure(ensure(result, 'textDocument'), 'publishDiagnostics').relatedInformation = true;
            for (let feature of this._features) {
                feature.fillClientCapabilities(result);
            }
            return result;
        }
        initializeFeatures() {
            let documentSelector = this._clientOptions.documentSelector;
            for (let feature of this._features) {
                feature.initialize(this._capabilities, documentSelector);
            }
        }
        handleRegistrationRequest(params) {
            return new Promise((resolve, reject) => {
                for (let registration of params.registrations) {
                    const feature = this._dynamicFeatures.get(registration.method);
                    if (!feature) {
                        reject(new Error(`No feature implementation for ${registration.method} found. Registration failed.`));
                        return;
                    }
                    const options = registration.registerOptions || {};
                    options.documentSelector = options.documentSelector || this._clientOptions.documentSelector;
                    const data = {
                        id: registration.id,
                        registerOptions: options
                    };
                    feature.register(this._method2Message.get(registration.method), data);
                }
                resolve();
            });
        }
        handleUnregistrationRequest(params) {
            return new Promise((resolve, reject) => {
                for (let unregistration of params.unregisterations) {
                    const feature = this._dynamicFeatures.get(unregistration.method);
                    if (!feature) {
                        reject(new Error(`No feature implementation for ${unregistration.method} found. Unregistration failed.`));
                        return;
                    }
                    feature.unregister(unregistration.id);
                }
                ;
                resolve();
            });
        }
        handleApplyWorkspaceEdit(params) {
            // This is some sort of workaround since the version check should be done by VS Code in the vscode.workspace.applyEdit.
            // However doing it here adds some safety since the server can lag more behind then an extension.
            let workspaceEdit = params.edit;
            let openTextDocuments = new Map();
            exports.vscode.workspace.textDocuments.forEach((document) => openTextDocuments.set(document.uri.toString(), document));
            let versionMismatch = false;
            if (workspaceEdit.documentChanges) {
                for (const change of workspaceEdit.documentChanges) {
                    if (change.textDocument.version && change.textDocument.version >= 0) {
                        let textDocument = openTextDocuments.get(change.textDocument.uri);
                        if (textDocument && textDocument.version !== change.textDocument.version) {
                            versionMismatch = true;
                            break;
                        }
                    }
                }
            }
            if (versionMismatch) {
                return Promise.resolve({ applied: false });
            }
            return exports.vscode.workspace.applyEdit(this._p2c.asWorkspaceEdit(params.edit)).then((value) => { return { applied: value }; });
        }
        ;
        logFailedRequest(type, error) {
            // If we get a request cancel don't log anything.
            if (error instanceof vscode_languageserver_protocol_1.ResponseError && error.code === vscode_languageserver_protocol_1.ErrorCodes.RequestCancelled) {
                return;
            }
            this.error(`Request ${type.method} failed.`, error);
        }
    }
    exports.BaseLanguageClient = BaseLanguageClient;
});
